package com.techfork.hutool.teck;

import java.awt.*;
import java.io.ByteArrayInputStream;
import java.io.CharArrayReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.net.URL;
import java.nio.charset.Charset;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

import javax.script.ScriptEngine;
import javax.script.ScriptException;

import cn.hutool.db.DbUtil;
import com.techfork.hutool.teck.base.*;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.core.bean.BeanDesc;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.builder.GenericBuilder;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.date.StopWatch;
import cn.hutool.core.img.ColorUtil;
import cn.hutool.core.img.FontUtil;
import cn.hutool.core.img.ImgUtil;
import cn.hutool.core.io.FileTypeUtil;
import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.IoUtil;
import cn.hutool.core.io.NioUtil;
import cn.hutool.core.io.StreamProgress;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.io.unit.DataSizeUtil;
import cn.hutool.core.lang.ConsoleTable;
import cn.hutool.core.lang.TypeReference;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.ZipUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.http.HtmlUtil;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONConfig;
import cn.hutool.json.JSONUtil;
import cn.hutool.script.ScriptUtil;
import cn.hutool.system.SystemUtil;
import lombok.experimental.ExtensionMethod;
import lombok.experimental.FieldNameConstants;
import lombok.extern.slf4j.Slf4j;

/**
 * 技术使用示例及说明
 */
@Slf4j
public class Usage {


    public static String getPath(String detail) {
        URL resource = ResourceUtil.getResource("");
        return resource.getPath() + detail;
    }


    /**
     * io 篇
     * 故事：小瓦小佳处理文件
     *  1. 小瓦同学想要快速的对流进行复制，又不想写样板代码，纠结中
     *      老板：瓦~文件拷贝了多少？
     *  2. 小佳同学想知道硬盘里某个文件的真实类型和文件大小~~~
     *  3. 小瓦同学要操作资源文件啦
     *  4. 小瓦小佳处理文件~~
     */
    public static void ioUtilTest() {
        // 1. 流的复制
        File temp = new File(getPath("io/temp.log"));
        File text = new File(getPath("io/text.log"));
        File multiName = new File(getPath("io/multiName.tar.gz"));
        String s = "test\nhello io util 中文\n";
        try {
            try (
                FileOutputStream outputStream1 = new FileOutputStream(File.createTempFile("io-1-util", ".temp"));
                FileOutputStream outputStream2 = new FileOutputStream(File.createTempFile("io-2-util", ".temp"));
                FileOutputStream outputStream3 = new FileOutputStream(File.createTempFile("io-3-util", ".temp"));
                FileWriter writer = new FileWriter(File.createTempFile("io-4-util", ".temp"));

                ByteArrayInputStream bs = new ByteArrayInputStream(s.getBytes(), 0, s.getBytes().length);
                CharArrayReader charArrayReader = new CharArrayReader(s.toCharArray());
            ) {

                IoUtil.copy(bs, outputStream1);
                bs.reset();
                IoUtil.copy(bs, outputStream2, 1024);
                IoUtil.copy(charArrayReader, writer);
                bs.reset();
                System.out.println(bs.available());
                NioUtil.copyByNIO(bs, outputStream3, 7, bs.available(), new StreamProgress() {
                    @Override
                    public void start() {
                        System.out.println("拷贝开始");
                    }

                    @Override
                    public void progress(long total, long progressSize) {
                        System.out.printf("拷贝过程（%d/%d）\n", progressSize, total);
                    }

                    @Override
                    public void finish() {
                        System.out.println("拷贝已结束");
                    }
                });
                System.out.println(bs.available());
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }

        // 2.文件类型
        System.out.println(FileTypeUtil.getType(temp));

        // 3.文件大小
        System.out.println(DataSizeUtil.parse("12k") >> 10);
        System.out.println(DataSizeUtil.format(1 << 22));

        // 4.资源
        String resPath = "application.properties";
        URL resource = ResourceUtil.getResource(resPath);
        System.out.println(resource);
        System.out.println(ResourceUtil.readUtf8Str(resPath));

        // 5.文件, 非常多的用法
        System.out.println(FileUtil.readLines(text, "UTF-8").size());

        System.out.println(FileNameUtil.getName(multiName));
        System.out.println(FileNameUtil.getPrefix(multiName));


        // 6.压缩
        ZipUtil.zip(getPath("io/zip"), getPath("io/zips/log.zip"));
    }

    /**
     * 构造
     * 故事：
     * 1. 小瓦尝试了一种很新的构造对象的方式
     */
    public static void builderUtilTest() {
        // map
        HashMap<String, String> colorMap = GenericBuilder.of(HashMap<String, String>::new)
            .with(Map::put, "red", "#FF0000")
            .with(Map::put, "yellow", "#FFFF00")
            .with(Map::put, "blue", "#0000FF").build();
        System.out.println(colorMap);

        TestObj objFromBuild = GenericBuilder.of(TestObj::new)
            .with(TestObj::setA, "a")
            .with(TestObj::setB, 1)
            .with(TestObj::setC, 1.0)
            .with(TestObj::setD, LocalDateTime.now())
            .build();
        System.out.println(objFromBuild);
    }

    /**
     * java bean
     * 故事：
     *  小佳公司都已经上市了，小瓦还在为VO、BO各种O的赋值烦恼
     */
    public static void beanUtilTest() {
        Class<TestObj> testObjClass = TestObj.class;
        BeanDesc beanDesc = BeanUtil.getBeanDesc(testObjClass);
        System.out.println(beanDesc);

        // 字段是否有 null 值
        TestObj bean = new TestObj();
        System.out.println(BeanUtil.hasNullField(bean));
        HashMap<Object, Object> objectHashMap = GenericBuilder.of(HashMap::new)
            .with(Map::put, "pField", "hello builder pField")
            .with(Map::put, "a", "hello builder a")
            .build();

        // 只注入父类继承的属性
        bean = BeanUtil.mapToBean(objectHashMap, testObjClass, false, CopyOptions.create().setEditable(TestObjP.class));
        System.out.printf("a: %s, pField: %s\n", BeanUtil.getFieldValue(bean, "a"), BeanUtil.getFieldValue(bean, "pField"));
    }


    /**
     * 集合相关
     * 故事：
     * 1. 小瓦在尝试一种很新的集合构造方式
     * 2. 小佳办了一个超市~~
     */
    public static void collectionUtilTest() {
        // gen
        String[] arr = {"", "a", "b", "c"};
        List<String> list = CollectionUtil.list(true, arr);
        HashSet<String> set = CollUtil.set(false, arr);
        System.out.println(list);

        // common
        CollUtil.addIfAbsent(list, "d-append");
        CollUtil.removeBlank(list);
        System.out.println(list);
        CollUtil.setOrAppend(list, 0, "a-update");
        CollUtil.addIfAbsent(list, "e-delete");
        System.out.println(list);
        CollUtil.removeAny(list, "e-delete");
        System.out.println(list);

        // sub
        System.out.println(CollUtil.sub(list, 0, 2));

        // zip
        System.out.println(CollUtil.zip(list, list));

        // join
        System.out.println(CollUtil.join(list, "..."));

        // 聚合

        Map<String, List<Double>> orderMap = new HashMap<>();

        List<Map<Object, Object>> orders = CollUtil.list(true,
                new Order("鸡蛋", 12.00),
                new Order("鸡蛋", 51.00),
                new Order("鸭脖", 82.00),
                new Order("塑料卫生纸", 33.33),
                new Order("塑料卫生纸", 43.33),
                new Order("塑料卫生纸", 53.33),
                new Order("塑料卫生纸", 63.33),
                new Order("塑料卫生纸", 73.33)
            ).stream()
            .peek(x -> {
                orderMap.compute(x.getGoodsName(), (k, v) -> {
                    if (v == null) v = new ArrayList<>();
                    v.add(x.getPrice());
                    return v;
                });
            })
            .map(x -> MapUtil.builder().put(x.getGoodsName(), x.getPrice()).build())
            .collect(Collectors.toList());

        System.out.println(orderMap);
        System.out.println(CollUtil.toListMap(orders));

        // Map List
        MapUtil.builder().build();
        ListUtil.list(true);

    }


    /**
     * 日期
     * 故事：
     *  1. 小佳的日历本~
     *  2. 小瓦的日程提示
     * @throws InterruptedException
     */
    public static void dateUtilTest() throws InterruptedException {

        // 日期格式没有自定义，这个工具类建议不使用
        // 用原生的也很方便
        // todo 可扩展
        String format = LocalDateTimeUtil.format(LocalDateTime.now(), "yyyy-MM-dd HH:mm:ss");
        System.out.println(format);

        // 计时器
        StopWatch a = StopWatch.create("a");
        StopWatch b = StopWatch.create("b");
        a.start("a-t1");
        TimeUnit.SECONDS.sleep(1);
        a.stop();
        a.start("a-t2");
        TimeUnit.SECONDS.sleep(1);
        a.stop();
        b.start("b-t1");
        TimeUnit.SECONDS.sleep(2);
        b.stop();
        System.out.println(a.prettyPrint());
        System.out.println(b.prettyPrint());
    }


    /**
     * 图像
     * 故事：
     *  小佳小瓦知识产权保护意识加强了
     */
    public static void imageUtilTest() {
        ImgUtil.pressText(new File(getPath("img/test.png")),
            new File(getPath("img/test_press_text.png")),
            "小佳~瓦",
            ColorUtil.getColor("20,0,0"),
            FontUtil.createFont("黑体", 70),
            50, 50, 0.9f
        );
    }

    /**
     * 字符串
     * 故事：
     *  1. 小佳被字符串绕晕的一天
     *  2. 小瓦在研究 fast-json 的 bug
     */
    public static void strUtilTest() {

        // str
        String org = "this is a demo, And you c1n test me";
        String org1 = " ";


        System.out.println(StrUtil.replace(org, "[A,1]", "a"));
        System.out.println(StrUtil.isNullOrUndefined(org1));
        System.out.println(StrUtil.isBlank(org1));
        System.out.println(StrUtil.isEmpty(org1));

        System.out.println(StrUtil.join("^", "a", "b", "c"));

        // json
        String jsonStr = JSONUtil.toJsonStr(new TestObj(), JSONConfig.create().setDateFormat("yyyy-MM-DD"));
        System.out.println(jsonStr);
        System.out.println(JSONUtil.toBean(jsonStr, TestObj.class));

        // json-泛型
        HttpResult<TestObj> httpResult = new HttpResult<>();
        httpResult.setData(new TestObj());
        httpResult.setDataList(ListUtil.of(new TestObj(), new TestObj()));
        String toJsonStr = JSONUtil.toJsonStr(httpResult);
        HttpResult<TestObjC> result = JSONUtil.toBean(toJsonStr, HttpResult.class);
        System.out.println(result);

        // 无泛型转换问题
        TypeReference<HttpResult<TestObjC>> resultTypeReference = new TypeReference<HttpResult<TestObjC>>() {
        };
        HttpResult<TestObjC> result2 = JSONUtil.toBean(toJsonStr, resultTypeReference, false);
        System.out.println(result2);

    }

    /**
     * 验证码
     * 故事：
     *  1. 小佳回家晚了一秒钟，小瓦不让小佳进门
     */
    public static void captchaUtilTest() {
        Image c919 = CaptchaUtil.createLineCaptcha(100, 50).createImage("C919");
        ImgUtil.write(c919, FileUtil.file(getPath("img/c919_captcha.png")));
    }

    /**
     * 定时任务
     *  故事：
     *      1. 听我说，滴答，滴答，滴答，hung~m
     * @throws InterruptedException
     */
    public static void taskUtilTest() throws InterruptedException {
        CronUtil.schedule("* * * * * *", (Task) () -> {
            System.out.println(System.currentTimeMillis());
        });
        CronUtil.schedule("* * * * * *", (Task) () -> {
            System.out.println("run task");
        });
        CronUtil.setMatchSecond(true);
        CronUtil.start();
        TimeUnit.SECONDS.sleep(8);
        CronUtil.stop();
    }

    /**
     * 系统
     * 故事:
     *  1. 小瓦的大脑设置被调乱了哦
     */
    public static void systemUtilTest() {
        ConsoleTable consoleTable = ConsoleTable.create().addHeader("监控项", "数值");
        Arrays.stream(ReflectUtil.getMethods(SystemUtil.class))
            .filter(m ->
                m.getParameterCount() == 0
            )
            .forEach(m -> {
                try {
                    consoleTable.addBody(m.getName(), StrUtil.sub(String.valueOf(m.invoke(SystemUtil.class)), 0, 30));
                } catch (Exception e) {
//                    System.err.println(e.getMessage());
                }
            });

        consoleTable.print();
    }

    /**
     * http
     * 故事：
     *  1. 小佳：瓦~iQiyi会员借我……
     * @throws ScriptException
     */
    public static void httpUtilTest() throws ScriptException {
        String s = HttpUtil.get("https://www.baidu.com");
//        System.out.println(s);
        // html
        String s1 = HtmlUtil.removeHtmlTag(s, "body", "script", "style", "!DOCTYPE html");
        System.out.println(s1);

        ScriptEngine jsEngine = ScriptUtil.getJsEngine();
        jsEngine.put("first", 100);
        System.out.println(jsEngine.eval("(function add(a,b){return first + a+b})(1,2)"));

        jsEngine.put("jsonStr", JSONUtil.toJsonStr(new TestObj("test java js engine")));
        System.out.println(jsEngine.eval(ResourceUtil.getReader("js/test.js", Charset.defaultCharset())));



    }

}


